#include "AffineTransform.hpp"
#include <math.h>

#include <iostream>



/***********************************************************************************************************/
/***********************************************************************************************************/
/***********************************************************************************************************/
/*** Registration :: Transformation */

Transformation::Transformation(const girl::tools::Image &image)
    :_image(image)
{}
Transformation::Transformation()
    :_image(girl::tools::Image())
{}
girl::tools::Image Transformation::transformed()
{
    return transformed(_image,_params);
}

girl::tools::Image Transformation::transformed(const girl::tools::Image & image)
{
    return transformed(image,_params);
}
girl::tools::Image Transformation::transformed(const girl::tools::Image & image,
                                                             const TransformationParameter &params)
{
    float radian = M_PI * (params.angle) / 180 ;

    girl::tools::Image out;

    // centre de la rotation
    int x0 = image.width()/2;
    int y0 = image.height()/2;

    out = image;
    for(int x =0 ; x < out.width(); x++)
    {
        for(int y =0 ; y < out.height(); y++)
        {
            girl::tools::Pixel blanc(255,255,255);
            out.setPixel(x,y,blanc);
        }
    }

    for(int x =0 ; x < image.width(); x++)
    {
        for(int y =0 ; y < image.height(); y++)
        {
            int x2 = round(cos(radian) * (x - x0) + sin(radian) * (y - y0) + x0) + params.dx;
            int y2 = round(cos(radian) * (y - y0) - sin(radian) * (x - x0) + y0) + params.dy;

            AffineTransform::clamp(x2,y2,image);

            out.setPixel(x2,y2,image.getPixel(x,y));

        }
     }
    return out;
}


/***********************************************************************************************************/
/***********************************************************************************************************/
/***********************************************************************************************************/
/***  TransformationParameter */

Transformation * Transformation::TransformationParameter::create(const girl::tools::Image & image)
{
   Transformation * trans = new Transformation(image);
   trans->setParams(*this);
   return trans;
}



/***********************************************************************************************************/
/***********************************************************************************************************/
/***********************************************************************************************************/
/*** AffineTransform */

AffineTransform::AffineTransform()
{
}

void AffineTransform::translated(const girl::tools::Image &image,
                                 int dx, int dy,
                                 girl::tools::Image &out)
{
    out = image;

    for(int x =0 ; x < out.width(); x++)
    {
        for(int y =0 ; y < out.height(); y++)
        {
            girl::tools::Pixel blanc(255,255,255);
            out.setPixel(x,y,blanc);
        }
    }
    for(int i = 0 ; i < image.width(); i++)
    {
        for(int j = 0 ; j < image.height(); j++)
        {
            int new_i = i + dx;
            int new_j = j + dy;
            clamp(new_i,new_j,out);
            out.setPixel(new_i,new_j,image.getPixel(i,j));
        }
    }
}

void AffineTransform::rotated(const girl::tools::Image &image,
                                            int angle,
                                            girl::tools::Image &out)
{


    float radian = M_PI * (angle) / 180 ;


    // centre de la rotation
    int x0 = image.width()/2;
    int y0 = image.height()/2;

    out = image;
    for(int x =0 ; x < out.width(); x++)
    {
        for(int y =0 ; y < out.height(); y++)
        {
            girl::tools::Pixel blanc(255,255,255);
            out.setPixel(x,y,blanc);
        }
    }

    for(int x =0 ; x < image.width(); x++)
    {
        for(int y =0 ; y < image.height(); y++)
        {
            int x2 = round(cos(radian) * (x - x0) + sin(radian) * (y - y0) + x0);
            int y2 = round(cos(radian) * (y - y0) - sin(radian) * (x - x0) + y0);

            clamp(x2,y2,image);

            out.setPixel(x2,y2,image.getPixel(x,y));

        }
     }
}

girl::tools::Image AffineTransform::resized(const girl::tools::Image &image, int factor)
{
    girl::tools::Image out(image.width()/factor, image.height()/factor, image.format());

    for(int x =0 ; x < image.width() - factor; x+=factor)
    {
        for(int y =0 ; y < image.height() - factor; y+=factor)
        {

            out.setPixel(x/factor,y/factor,image.getPixel(x,y));
        }
     }
    return out;
}

